package net.xdclass.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.config.CouponRabbitMQConfig;
import net.xdclass.entity.CouponRecord;
import net.xdclass.entity.CouponTask;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.enums.CouponStateEnum;
import net.xdclass.enums.ProductOrderStateEnum;
import net.xdclass.enums.StockTaskStateEnum;
import net.xdclass.exception.BizException;
import net.xdclass.feign.ProductOrderFeignService;
import net.xdclass.interceptor.LoginInterceptor;
import net.xdclass.mapper.CouponRecordMapper;
import net.xdclass.mapper.CouponTaskMapper;
import net.xdclass.model.CouponRecordMessage;
import net.xdclass.model.LoginUser;
import net.xdclass.request.LockCouponRecordRequest;
import net.xdclass.service.ICouponRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.xdclass.utils.JsonData;
import net.xdclass.vo.CouponRecordVO;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author lixin
 * @since 2024-08-23
 */
@Service
@Slf4j
public class CouponRecordServiceImpl extends ServiceImpl<CouponRecordMapper, CouponRecord> implements ICouponRecordService {

    @Autowired
    private CouponRecordMapper couponRecordMapper;

    @Autowired
    private CouponTaskMapper couponTaskMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private CouponRabbitMQConfig couponRabbitMQConfig;

    @Autowired
    private ProductOrderFeignService orderFeignService;

    /**
     * 分页查询领券记录
     * @param page
     * @param size
     * @return
     */
    @Override
    public Map<String, Object> page(int page, int size) {

        LoginUser loginUser = LoginInterceptor.threadLocal.get();

        //封装分页信息
        Page<CouponRecord> pageInfo = new Page<>(page, size);

        Page<CouponRecord> couponRecordPage = couponRecordMapper.selectPage(pageInfo, new QueryWrapper<CouponRecord>().eq("user_id", loginUser.getId())
                .orderByDesc("create_time"));

        Map<String, Object> pageMap = new HashMap<>(3);
        pageMap.put("total_record", couponRecordPage.getTotal());
        pageMap.put("total_page", couponRecordPage.getPages());
        pageMap.put("current_data", couponRecordPage.getRecords().stream().map(obj -> beanProcess(obj)).collect(Collectors.toList()));
        return pageMap;
    }

    /**
     * 根据id找详情
     * @param recordId
     * @return
     */
    @Override
    public CouponRecordVO findByid(long recordId) {
        LoginUser loginUser = LoginInterceptor.threadLocal.get();
        CouponRecord couponRecord = couponRecordMapper.selectOne(new QueryWrapper<CouponRecord>()
                .eq("id", recordId)
                .eq("user_id", loginUser.getId()));

        if (couponRecord == null){
            return null;
        }
        return beanProcess(couponRecord);
    }

    /**
     * 锁定优惠券
     * 1.锁定优惠券记录
     * 2.task表插入记录
     * 3.发送延迟消息
     * @param recordRequest
     * @return
     */
    @Override
    public JsonData lockCouponRecords(LockCouponRecordRequest recordRequest) {
        String orderOutTradeNo = recordRequest.getOrderOutTradeNo();
        List<Long> lockCouponRecordIds = recordRequest.getLockCouponRecordIds();
        LoginUser loginUser = LoginInterceptor.threadLocal.get();

        int updateRows = couponRecordMapper.lockUserStateBatch(loginUser.getId(), CouponStateEnum.USED.name(), lockCouponRecordIds);

        List<CouponTask> couponTaskList = lockCouponRecordIds.stream().map(obj -> {
            CouponTask couponTask = new CouponTask();
            couponTask.setCreateTime(LocalDateTime.now());
            couponTask.setOutTradeNo(orderOutTradeNo);
            couponTask.setCouponRecordId(obj);
            couponTask.setLockState(StockTaskStateEnum.LOCK.name());
            return couponTask;
        }).collect(Collectors.toList());

        int rows = couponTaskMapper.insertBatch(couponTaskList);

        log.info("优惠券记录锁定rows={}", updateRows);
        log.info("新增优惠券记录task insertRows={}",rows);

        if (lockCouponRecordIds.size() == rows && rows == updateRows){
            //发送延迟消息

            for (CouponTask couponTask : couponTaskList) {
                CouponRecordMessage couponRecordMessage = new CouponRecordMessage();
                couponRecordMessage.setOutTradeNo(orderOutTradeNo);
                couponRecordMessage.setTaskId(couponTask.getId());

                rabbitTemplate.convertAndSend(couponRabbitMQConfig.getEventExchange(), couponRabbitMQConfig.getCouponReleaseDelayRoutingKey(), couponRecordMessage);

                log.info("优惠券锁定消息发送成功: {}", couponRecordMessage.toString());
            }


            return JsonData.buildSuccess();
        }else {
            throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
        }
    }

    /**
     * 释放优惠券记录
     * 1.查询task工作单是否存在
     * 2.查询订单状态
     * @param recordMessage
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean releaseCouponRecord(CouponRecordMessage recordMessage) {
        //查询工作单是否存在
        CouponTask couponTask = couponTaskMapper.selectOne(new QueryWrapper<CouponTask>().eq("id", recordMessage.getTaskId()));

        if (couponTask == null){
            log.info("工作单不存在, 消息:{}", recordMessage);
            return true;
        }

        //lock状态才处理
        if (couponTask.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())){
            //查询订单转态
            JsonData jsonData = orderFeignService.queryProductOrderState(recordMessage.getOutTradeNo());

            if (jsonData.getCode() == 0){
                //正常响应，判断订单状态
                String state = jsonData.getData().toString();
                if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)){
                    //状态为new新建状态,则返回给消息队列重新投递
                    log.warn("订单状态是NEW, 返回给消息队列，重新投递: {}", recordMessage);
                    return false;
                }

                if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)){
                    //已经支付，修改task状态为finish
                    couponTask.setLockState(StockTaskStateEnum.FINISH.name());
                    couponTaskMapper.update(couponTask, new QueryWrapper<CouponTask>().eq("id", recordMessage.getTaskId()));
                    log.info("订单已经支付,修改库存锁定工作单为FINISH状态: {}", recordMessage);
                    return true;
                }
            }

            //订单不存在, 或者订单被取消,确认消息即可,修改task转态为CANCEL, 恢复优惠券记录为NEW状态
            log.warn("订单不存在, 或者订单被取消,确认消息即可,修改task转态为CANCEL, 恢复优惠券记录为NEW状态, message:{}", recordMessage);
            couponTask.setLockState(StockTaskStateEnum.CANCEL.name());
            couponTaskMapper.update(couponTask, new QueryWrapper<CouponTask>().eq("id", recordMessage.getTaskId()));

            //恢复优惠卷记录为NEW
            couponRecordMapper.updateState(couponTask.getCouponRecordId(), CouponStateEnum.NEW.name());


            return true;
        }else {
            log.warn("工作单状态不是lock， state={}, 消息体:{}", couponTask.getLockState(), recordMessage);
            return true;
        }
    }

    private CouponRecordVO beanProcess(CouponRecord couponRecord) {

        CouponRecordVO couponRecordVO = new CouponRecordVO();
        BeanUtils.copyProperties(couponRecord, couponRecordVO);
        return couponRecordVO;
    }
}
